<?php

// +----------------------------------------------------------------------
// | Static Plugin for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2024 ThinkAdmin [ thinkadmin.top ]
// +----------------------------------------------------------------------
// | 官方网站: https://thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// | 免责声明 ( https://thinkadmin.top/disclaimer )
// +----------------------------------------------------------------------
// | gitee 代码仓库：https://gitee.com/zoujingli/think-plugs-static
// | github 代码仓库：https://github.com/zoujingli/think-plugs-static
// +----------------------------------------------------------------------

namespace app\index\controller\info;

use app\common\model\paths\ClassTaskModel;
use app\common\model\paths\EmployInfoModel;
use app\common\model\paths\EmployLogInfoModel;
use app\common\model\paths\EmployLogModel;
use app\common\model\paths\EmployModel;
use app\common\model\paths\TaskChapterModel;
use app\common\model\paths\TaskModel;
use app\common\model\paths\UserClassModel;
use app\common\model\paths\UserStudyGoldModel;
use app\index\controller\BaseIndex;
use think\admin\extend\DataExtend;
use think\admin\extend\ToolsExtend;
use think\admin\service\ProcessService;


class Index extends BaseIndex
{

    public $need_login = true;

    public function index()
    {
        $this->title = lang('实践项目');
        $employ_id = $this->request->get('employ_id'); // 实践id
        $task_id   = $this->request->get('task_id');  // 课程id
        $employ_info_id   = $this->request->get('employ_info_id', 0);  // 关卡id
        // 课程信息
        $task_head = TaskModel::mk()->where('id', $task_id)->find();
        // 实战头表
        $employ    = EmployModel::mk()->where('id', $employ_id)->find();


        if ($employ_info_id) {

            $employInfo = EmployInfoModel::mk()->where('id', $employ_info_id)->where('app_id', $employ_id)->where('status', 1)->order('sort', 'asc')->find();

            $count_select = EmployInfoModel::mk()->where('app_id', $employ_id)->where('level', 1)->where('status', 1)->order('sort', 'asc')->select();

            $count = 1;
            foreach ($count_select as $item) {

                if ($item->id <> $employ_info_id) {
                    $count ++;
                } else {
                    break;
                }

            }

        } else {
            // 根据实战的的学习记录，找到已经学习的章节
            $levels_ids = EmployLogModel::mk()->where('index_user_id', $this->user_id)->where('task_id', $task_id)->where('employ_id', $employ_id)->column('levels_id');

            // 找到需要学习的章节
            $employInfo = EmployInfoModel::mk()->whereNotIn('id', $levels_ids)->where('pid', 0)->where('app_id', $employ_id)->where('status', 1)->order('sort', 'asc')->find();

            // 判断是第几关
            $count = count($levels_ids) + 1;
        }

        $this->tab_arr = EmployInfoModel::getTypeName();

        $this->info = [];
        $this->is_over = 0;
        if ($employInfo) {
            foreach ($this->tab_arr as $key => $item) {
                // 实战章节内容信息
                $data_arr         = EmployInfoModel::mk()->where('pid', $employInfo->id)->where('type', $key)->select()->toArray();
                $this->info[$key] = DataExtend::arr2table($data_arr);
            }
            $employInfo['title'] = "第{$count}关：{$employInfo['title']}";

            foreach ($this->info[2] as &$item) {
                $item['content'] = json_encode($item['content']);
            }

        } else {
            $employInfo['title'] = '实战完毕';
            $this->is_over = 1;
        }

       // halt($this->info);

        // 实战头表
        $this->employ       = $employ;
        // 实战章节信息
        $this->employInfo   = $employInfo ?? [];

        $this->task_id      = $task_id;
        $this->task_head    = $task_head;
        // 会员消息
        $this->user_info    = $this->userInfo;
        // 商城和系统内容
        $path = public_path().'other.txt';
        $file = file_get_contents($path);
        $data = json_decode($file, true);

        $shop_replace = [
            '{account}'    => $this->userInfo['mobile'],
            '{password}'    => $this->userInfo['password_plaintext'],

        ];
        $this->content_shop   = str_replace(array_keys($shop_replace), array_values($shop_replace), $data['shop']);

        $this->content_system = $data['system'];
        $this->content_export_declaration = $data['export_declaration'];

        $this->fetch();
    }


    public function getTaskList ()
    {
        $task_id = $this->request->get('task_id');
        $employ_id = $this->request->get('employ_id');

        /*$task_head    = TaskModel::mk()->where('id', $task_id)->find();*/
        $task_chapter = TaskChapterModel::mk()->field('title,id,pid')->where('task_id', $task_id)->where('status', 1)->where('pid',  0)->order('sort', 'asc')->select()->toArray();
        TaskChapterModel::mk()->field('title,id,pid')->where('task_id', $task_id)->where('status', 1)->where('employ_id', '>', 0)->order('sort', 'asc')->select()->each(function ($item) use (&$task_employ) {
            $task_employ[$item['pid']][] = $item->toArray();
        });

        $task_chapter = TaskChapterModel::mk()->field('title,id,pid,employ_id')->where('task_id', $task_id)->where('status', 1)->where('employ_id', '>', 0)->order('sort', 'asc')->select();

        $employ_ids = $task_chapter->column('employ_id');

        EmployInfoModel::mk()->whereIn('app_id', $employ_ids)->where('pid', 0)->order('sort', 'asc')->select()->each(function ($item) use (&$employ_info) {
            $employ_info[$item['app_id']][] = $item->toArray();
        });

        $list = [];
        foreach ( $task_chapter as $item) {

            if ( isset($employ_info[$item['employ_id']]) ){
                $item['sub'] = $employ_info[$item['employ_id']] ;
                $list[] = $item;
            }
        }

        $this->employ_info = $list;
        $this->employ_id   = $employ_id;
        $this->task_id     = $task_id;

        $this->fetch();
    }

    /**
     * 执行代码
     *
     * @return void
     */
    public function activeCode()
    {
        $code      = $this->request->post('code');
        $employ_id = $this->request->post('employ_id'); // 实践id
        $answer_id = $this->request->post('answer_id'); // 答案id

        $task_id   = $this->request->post('task_id'); // 课程id

        $employ_obj = EmployInfoModel::mk()->where('id', $answer_id)->find();


        $command      = $this->getLanguageCommand($employ_obj->language);
        $file_command = $this->getFileCommand($employ_obj);
        
        // 执行原始文件 并获得结果
        $answer_data = ProcessService::exec("{$command} {$file_command}");
        
     /*   if ($this->user_id == 15) {
            halt($answer_data);
        }*/
        // 根据用户写的代码，构造可执行文件
        $code_command   = $this->getCodeCommand($code, $employ_obj);

        $code_result = ProcessService::exec("{$command} {$code_command}");
        
        // 删除生成的可执行文件 （包含目录） 用于净化系统
        ToolsExtend::removeEmptyDirectory(public_path("code/{$this->user_id}").date("Ymd"));
      
        $next = 0; // 是否跳转
        $gold_msg = "";

        if ($code_result == $answer_data) {

            // 判断是否 已经做过了  当前的问题
            $employLogInfo = EmployLogInfoModel::mk()->where('index_user_id', $this->user_id)->where('levels_id', $employ_obj->pid)->where('answer_id', $answer_id)->find();

            // 记录分数
            // $gold = EmployInfoModel::mk()->where('id', $employ_obj->pid)->value('gold'); // 用户id
            $gold = $employ_obj->gold;

            if  (!$employLogInfo) { // 如果没做过了
                // 写入 日志详情， 记录答案的日志
                $this->insertEmployLogInfo($answer_id , $employ_obj->pid);

                // 先判断是否做完所有的题目
                $answer_ids = EmployLogInfoModel::mk()->where('index_user_id', $this->user_id)->where('levels_id', $employ_obj->pid)->order('answer_id', 'asc')->column('answer_id');
                // 获得当前关卡的所有答案id
                $answer_ids_arr = EmployInfoModel::where('pid', $employ_obj->pid)->where('type', 2)->where('status', 1)->order('id', 'asc')->column('id');
                // 写入日志分数
                $this->insertEmployLog($task_id, $employ_id, $employ_obj->pid, $gold);

                // 判断 答案是否全部做完
                $intersection = array_intersect($answer_ids, $answer_ids_arr);

                if (count($intersection) === count($answer_ids_arr)) {

                    $gold_msg = " ,自动跳转下一关";
                    $next = 1;
                }

                // 根据实战id 找到章节id
                $chapter_arr = TaskChapterModel::mk()->field('id, pid')->where('task_id', $task_id)->where('employ_id', $employ_id)->find();

                // 找到 用户学习的这个课程属于那些班级
                // 课程属于的班级
                 ClassTaskModel::mk()->where('task_id', $task_id)->select()->each(function ($item) use (&$class_task, &$class_task_ids) {
                     $class_task_ids[] = $item->class_id;
                     $class_task[$item->class_id] = $item->toArray();
                }); //column('class_id');
                // 用户拥有的班级
                $class_user = UserClassModel::mk()->where('index_user_id', $this->user_id)->column('class_id');

                $class_ids = array_intersect($class_task_ids, $class_user);

                foreach ($class_ids as $class_id) {
                    // 将答案记录到记录表
                    $studyGold = UserStudyGoldModel::where('index_user_id', $this->user_id)->where('task_id', $task_id)->where('class_id', $class_id)->where('task_chapter_id', $chapter_arr['id'] ?? 0)->find();

                    if (!$studyGold ) {

                        $studyGold = new UserStudyGoldModel();

                        $studyGold->platform_id     = $class_task[$class_id]['platform_id'] ?? 0;
                        $studyGold->user_id         = $class_task[$class_id]['user_id']    ?? 0;
                        $studyGold->index_user_id   = $this->user_id;
                        $studyGold->task_id         = $task_id;
                        $studyGold->task_chapter_id = $chapter_arr['id'] ?? 0;
                        $studyGold->task_chapter_pid = $chapter_arr['pid'] ?? 0;
                        $studyGold->employ_id       = $employ_id;
                        $studyGold->employ_gold     = 0;
                        $studyGold->total_gold      = 0;
                        $studyGold->class_id        = $class_id;
                    }
                    $studyGold->employ_gold += $gold;
                    $studyGold->total_gold  += $gold;

                    $studyGold->save();
                }
            }

            $layer_msg = "答案正确,获得 {$gold}分 ". $gold_msg;
            $show_msg  = "答案正确：".$code_result;

            $this->success('成功', [ 'layer_msg' => $layer_msg, 'show_msg' => $show_msg, 'next'=>$next, 'answer'=>$answer_data, 'url'=>url('index/info.index/index',['employ_id'=>$employ_id, 'task_id'=> $task_id])]);
        } else {
            $layer_msg = "答案错误";
            $show_msg  = "答案错误：".$code_result;

            $this->error('error', [ 'layer_msg' => $layer_msg, 'show_msg' => $show_msg, 'next'=>0, 'answer'=>$answer_data]);
        }
    }



    /**
     * 实战关卡日志记录
     * @param int  $answer_id 答案 id
     * @param int  $levels_id 关卡id
     * @return void
     */
    protected function insertEmployLogInfo ($answer_id, $levels_id)
    {

        $employLogInfo = new EmployLogInfoModel();

        $employLogInfo->answer_id      = $answer_id; // 答案id
        $employLogInfo->levels_id      = $levels_id; // 关卡id
        $employLogInfo->index_user_id  = $this->user_id;

        $employLogInfo->save();

    }

    /**
     * 写入积分日志
     *
     * @return void
     */
    private function insertEmployLog ($task_id, $employ_id, $pid, $gold)
    {
        $logs = EmployLogModel::mk()->where('task_id', $task_id)->where('employ_id', $employ_id)->where('levels_id', $pid)->where('index_user_id', $this->user_id)->find();

        if (!$logs) {

            $logs = new EmployLogModel();

            $logs->task_id          =  $task_id;
            $logs->employ_id        =  $employ_id; // 实战id
            $logs->levels_id        =  $pid; // 关卡id
            $logs->index_user_id    =  $this->user_id; // 用户id
            $logs->gold             =  0;
        }

        $logs->gold  +=   $gold;
        $logs->save();
    }


    private function mkdirActive ($path)
    {
        // 检查目录是否存在
        if (!is_dir($path)) mkdir($path, 0755, true);
    }

    private function getFileCommand ($employ_obj)
    {
        $file_command = public_path().$employ_obj->file_path;
        
        if ($employ_obj->language == 'java') {
            // 获得文件名 不包含后缀
            $file_path = pathinfo($employ_obj->file_path, PATHINFO_DIRNAME);
            $file_name = pathinfo($employ_obj->file_path, PATHINFO_FILENAME);

            $file_command = public_path().$file_path.' '.$file_name;
        }

        return $file_command;
    }

    /**
     * 生成可执行文件并返回路径
     *
     * @param string $code
     * @param object $employ_obj
     * @return string
     */
    private function getCodeCommand ($code, $employ_obj)
    {
        // 获得文件名 不包含后缀
        $file_name = pathinfo($employ_obj->file_path, PATHINFO_FILENAME  );
        // 获得文件路径
        $code_path = public_path("code/{$this->user_id}").date("Ymd")."/".mt_rand(100,999);
        //$code_path = public_path("code/{$this->user_id}").date("Ymd")."/".mt_rand(100,999);
        // 拼接成文件路径
        $file_path_name = "{$code_path}/{$file_name}.{$employ_obj->language}";

        // 构造文件内容
        $file_content = '';
        if ($employ_obj->language == 'php') {
            $file_content ="<?php {$code} ";
        }
        if ($employ_obj->language == 'java' || $employ_obj->language == 'py') {
            $file_content = $code;
        }
        // 检查目录并创建
        $this->mkdirActive(dirname($file_path_name));
        file_put_contents($file_path_name,$file_content);

        if ($employ_obj->language == 'java') {
            // 如果是java 还需要编译
            ProcessService::exec("javac {$file_path_name}");

            $file_path_name = "{$code_path}  {$file_name}";
        }

        return $file_path_name;
    }

    private function getLanguageCommand ($language)
    {
        // 找到文件后缀
        switch ($language) {
            case 'php':
                // 执行原始文件 并获得结果
                $language = "php";
                break;
            case 'java':
                $language = "java -cp";
                // 获得编译后的文件名字
                break;
            case 'py':
                $language = "python";
                break;
            default:
                $language = "php";
        }

        return $language;
    }
}